package com.randb.easyhttp.cookie;

import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import okhttp3.Cookie;
import okhttp3.HttpUrl;

/**
 * User: RandBII
 * Date: 2020/5/13
 * Description:
 */
public class PersistentCookieStore {

    private static final String COOKIE_PREFERS = "Cookie_Prefers";

    private final Map<String, ConcurrentHashMap<String, Cookie>> cookies;
    private final SharedPreferences cookiePrefers;

    public PersistentCookieStore(Context context) {
        cookiePrefers = context.getSharedPreferences(COOKIE_PREFERS, 0);
        cookies = new HashMap<>();
        Map<String, ?> mapPrefers = cookiePrefers.getAll();
        for (Map.Entry<String, ?> entry : mapPrefers.entrySet()) {
            String[] cookieNames = TextUtils.split((String) entry.getValue(), ",");
            for (String name : cookieNames) {
                String encodedCookie = cookiePrefers.getString(name, null);
                if (encodedCookie != null) {
                    Cookie decodeCookie = decodeCookie(encodedCookie);
                    if (decodeCookie != null) {
                        if (!cookies.containsKey(entry.getKey())) {
                            cookies.put(entry.getKey(), new ConcurrentHashMap<String, Cookie>());
                        }
                        cookies.get(entry.getKey()).put(name, decodeCookie);
                    }
                }
            }
        }

    }

    private Cookie decodeCookie(String cookieString) {
        byte[] bytes = hexStringToByteArray(cookieString);
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        Cookie cookie = null;
        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
            cookie = ((SerializableOkHttpCookies) objectInputStream.readObject()).getCookies();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cookie;

    }


    private byte[] hexStringToByteArray(String cookieString) {
        int length = cookieString.length();
        byte[] data = new byte[length / 2];

        for (int i = 0; i < length; i += 2) {
            data[i / 2] = (byte) ((Character.digit(cookieString.charAt(i), 16) << 4)
                    + (Character.digit(cookieString.charAt(i + 1), 16)));
        }
        return data;
    }


    protected String getCookieToke(Cookie cookie) {
        return cookie.name() + "@" + cookie.domain();
    }

    public void add(HttpUrl url, Cookie cookie) {
        String name = getCookieToke(cookie);

        if (!cookies.containsKey(url.host())) {
            cookies.put(url.host(), new ConcurrentHashMap<String, Cookie>());
        }
        if (cookies.containsKey(url.host())) {
            cookies.get(url.host()).remove(name);
        }
        // 是否保存到SP 文件中
        if (cookie.persistent()) {
            SharedPreferences.Editor prefersWriter = cookiePrefers.edit();
            prefersWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));
            prefersWriter.putString(name, encodeCookie(new SerializableOkHttpCookies(cookie)));
            prefersWriter.apply();
        } else {
            SharedPreferences.Editor prefersWriter = cookiePrefers.edit();
            prefersWriter.remove(url.host());
            prefersWriter.remove(name);
            prefersWriter.apply();

        }

    }


    private String encodeCookie(SerializableOkHttpCookies serializableCookie) {
        if (serializableCookie == null) return null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream outputStream = new ObjectOutputStream(bos);
            outputStream.writeObject(serializableCookie);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

        return byteArrayToHexString(bos.toByteArray());
    }


    private String byteArrayToHexString(byte[] toByteArray) {
        StringBuilder builder = new StringBuilder(toByteArray.length * 2);

        for (byte b : toByteArray) {
            int v = b & 0xFF;// 符号位变为 1
            if (v < 16) {
                builder.append('0');
            }
            builder.append(Integer.toHexString(v));

        }

        return builder.toString();

    }


    public boolean remove(HttpUrl url, Cookie cookie) {

        String name = getCookieToke(cookie);
        if (cookies.containsKey(url.host()) &&
                cookies.get(url.host()).containsKey(name)) {
            cookies.get(url.host()).remove(name);
            SharedPreferences.Editor editor = cookiePrefers.edit();
            if (cookiePrefers.contains(name)) {
                editor.remove(name);
            }
            editor.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));
            editor.apply();
            return true;
        } else {
            return false;
        }
    }


    public void addCookies(List<Cookie> cookies) {
        for (Cookie cookie : cookies) {
            String domain = cookie.domain();
            ConcurrentHashMap<String, Cookie> domainCookies = this.cookies.get(domain);
            if (domainCookies == null) {
                domainCookies = new ConcurrentHashMap<>();
                this.cookies.put(domain, domainCookies);
            }
        }
    }


    public List<Cookie> get(HttpUrl url) {
        ArrayList<Cookie> ret = new ArrayList<>();
        if (cookies.containsKey(url.host())) {
            ret.addAll(cookies.get(url.host()).values());
        }
        return ret;
    }


}
